Skip to content

perf(wasm-privacy-coin): JIT-compile WASM + cache module/pool instances#322

Merged
OttoAllmendinger merged 1 commit into
masterfrom
otto/T1-3728-jit-compile-wasm-cache
Jul 21, 2026
Merged

perf(wasm-privacy-coin): JIT-compile WASM + cache module/pool instances#322
OttoAllmendinger merged 1 commit into
masterfrom
otto/T1-3728-jit-compile-wasm-cache

Conversation

@OttoAllmendinger

@OttoAllmendinger OttoAllmendinger commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

The shielded merkle tree test suite that consumes this package (MerkleTreeServiceTest, MerkleTreePruningTest, MerkleTreeEndToEndTest) was spending ~452s — almost entirely in WASM module setup, not actual tree operations. This PR makes those tests ~41x faster (452s → 10.9s) with three layers of optimization in wasm-privacy-coin.

Root cause

WasmBridge re-parsed the 466 KB privacy_coin.wasm binary and re-instantiated a fresh Chicory Instance on every ShieldedMerkleTree creation (~14s per cycle). Chicory 1.1.1 was interpreter-only, so even after caching, interpreted WASM execution dominated the remainder.

Changes

  1. Module caching (WasmBridge.java) — the parsed WasmModule is cached in a static volatile field (immutable, safely shared across threads). Only the first WasmBridge() pays the parse cost.

  2. Instance pooling (WasmBridge.java) — a ConcurrentLinkedDeque<Instance> reuses Chicory Instances. On close(), drop_tree drops the in-WASM tree and the Instance returns to the pool. The next WasmBridge() borrows it; from_frontier/from_state re-initializes the tree state in the existing linear memory. Failed init uses discard() to avoid polluting the pool with a dirty Instance.

  3. JIT compiler (pom.xml + WasmBridge.java) — upgraded Chicory 1.1.1 → 1.7.5 and added the compiler module. MachineFactoryCompiler.compile(module) JIT-compiles all WASM functions to JVM bytecode once per JVM; the resulting Machine replaces the interpreter, giving native-speed execution that the JVM C2 JIT further optimizes.

ShieldedMerkleTree.close() now delegates to WasmBridge.close() (which drops the tree + pools the instance), and create() uses discard() on init failure.

Results (downstream shielded merkle tree test suite)

Test class Before After Speedup
MerkleTreeServiceTest (15 tests) 213s 2.96s 72x
MerkleTreePruningTest (3 tests) 194s 3.38s 57x
MerkleTreeEndToEndTest (2 tests) 45s 4.57s 10x
Total 452s 10.9s 41x

Verification

  • All 41 wasm-privacy-coin tests pass.
  • The downstream consumer's merkle tree tests pass.
  • The Chicory version bump (1.1.1 → 1.7.5) is a breaking change for any consumer still on 1.1.1.

Refs: T1-3728

@linear-code

linear-code Bot commented Jul 20, 2026

Copy link
Copy Markdown

T1-3728

@OttoAllmendinger
OttoAllmendinger force-pushed the otto/T1-3728-jit-compile-wasm-cache branch from 4a0d789 to ebfa3fc Compare July 20, 2026 18:05
The shielded merkle tree test suite spent ~452s, almost entirely in
WASM module setup rather than tree operations. Three layers of fix:

1. Module caching — the parsed WasmModule is cached in a static volatile
   field (immutable, safely shared). Only the first WasmBridge pays the
   parse cost; subsequent trees reuse it.

2. Instance pooling — a ConcurrentLinkedDeque reuses Chicory Instances.
   close() drops the in-WASM tree via drop_tree and returns the Instance
   to the pool; the next WasmBridge borrows it and from_frontier /
   from_state re-initializes the tree state. Failed init uses discard()
   to avoid polluting the pool with a dirty Instance.

3. JIT compiler — upgraded Chicory 1.1.1 -> 1.7.5 and added the compiler
   module. MachineFactoryCompiler translates all WASM functions to JVM
   bytecode once per JVM, replacing the interpreter with native-speed
   execution that the JVM C2 JIT further optimizes.

Results on a downstream shielded merkle tree test suite that consumes
this package:
  MerkleTreeServiceTest    213s -> 2.96s  (72x)
  MerkleTreePruningTest    194s -> 3.38s  (57x)
  MerkleTreeEndToEndTest    45s -> 4.57s  (10x)
  Total                   452s -> 10.9s  (41x)

All 41 wasm-privacy-coin tests pass, plus the downstream consumer's
merkle tree tests. The Chicory version bump (1.1.1 -> 1.7.5) is a
breaking change for any consumer still on 1.1.1.

Refs: T1-3728
@OttoAllmendinger
OttoAllmendinger force-pushed the otto/T1-3728-jit-compile-wasm-cache branch from ebfa3fc to 418a75d Compare July 21, 2026 08:16
@OttoAllmendinger
OttoAllmendinger marked this pull request as ready for review July 21, 2026 08:47
@OttoAllmendinger
OttoAllmendinger requested a review from a team as a code owner July 21, 2026 08:47
@OttoAllmendinger
OttoAllmendinger merged commit 204625c into master Jul 21, 2026
15 checks passed
@OttoAllmendinger
OttoAllmendinger deleted the otto/T1-3728-jit-compile-wasm-cache branch July 21, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants